package nl.dxn.tunnel.server;

import nl.dxn.tunnel.CollectionUtils;
import nl.dxn.tunnel.enums.ProxyTypeEnum;
import nl.dxn.tunnel.server.cache.AgentChannelManager;
import nl.dxn.tunnel.server.cache.AgentServerDto;
import nl.dxn.tunnel.server.config.HttpConfigProperties;
import nl.dxn.tunnel.server.config.ProxyConfig;
import nl.dxn.tunnel.server.config.TcpConfigProperties;
import nl.dxn.tunnel.server.proxy.HttpServer;
import nl.dxn.tunnel.server.proxy.ProxyServer;
import nl.dxn.tunnel.server.proxy.TcpServer;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class ServerApp {
    private static final Logger logger = LoggerFactory.getLogger(ServerApp.class);
    private final List<HttpServer> httpList = new ArrayList<>();
    private final List<TcpServer> tcpList = new ArrayList<>();

    private ProxyServer proxyServer;

    private ProxyConfig proxyConfig;

    public ServerApp()
    {
        Runtime.getRuntime().addShutdownHook(new Thread(this::destroy));

        File file = new File(Constants.getContextPath(),"/config/server.yml");
        logger.info("加载文件地址：{}",file.getPath());
        if(file.exists()) {
            try (FileInputStream fis = new FileInputStream(file);
                 InputStreamReader isr = new InputStreamReader(fis)) {
                this.proxyConfig = new Yaml().loadAs(isr, ProxyConfig.class);
            } catch (Exception e) {
                logger.error("",e);
            }
        }
        else
        {
            InputStream resource = ClassLoader.getSystemResourceAsStream("server.yml");
            if (resource != null) {
                logger.info("加载文件地址：getSystemResourceAsStream,server.yml");
                this.proxyConfig = new Yaml().loadAs(resource, ProxyConfig.class);
            }
        }
    }

    public void destroy() {

        if (proxyServer != null) {
            try {
                proxyServer.destroy();
            }
            catch (Exception exception)
            {
                logger.error("",exception);
            }
        }

        for (TcpServer tcpServer : tcpList) {
            try {
                tcpServer.destroy();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        for (HttpServer httpServer : httpList) {
            try {
                httpServer.destroy();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void run() {
        try {
            if (proxyConfig == null) {
                System.exit(-1);
                return;
            }
            List<HttpConfigProperties> http = proxyConfig.getHttp();
            List<TcpConfigProperties> tcp = proxyConfig.getTcp();

            if (CollectionUtils.isEmpty(http) && CollectionUtils.isEmpty(tcp)) {
                return;
            }

            String checkServerResult = checkServerName(http,tcp);
            if(StringUtils.isNotBlank(checkServerResult))
            {
                logger.info(checkServerResult);
                System.exit(-1);
                return;
            }

            proxyServer = new ProxyServer(proxyConfig.getAgentIp(), proxyConfig.getAgentPort(), proxyConfig.getAgentKeyMap());
            boolean runProxyApp = proxyServer.run();
            if (!runProxyApp) {
                System.exit(-1);
                return;
            }

            if (!CollectionUtils.isEmpty(http)) {
                for (HttpConfigProperties httpConfigProperties : http) {
                    HttpServer httpServer = new HttpServer(httpConfigProperties);
                    boolean isRun = httpServer.run();
                    if (!isRun) {
                        System.exit(-1);
                        return;
                    }
                    httpList.add(httpServer);
                }
            }

            if (!CollectionUtils.isEmpty(tcp)) {
                for (TcpConfigProperties tcpProperties : tcp) {
                    TcpServer tcpServer = new TcpServer(tcpProperties);
                    boolean isRun = tcpServer.run();
                    if (!isRun) {
                        System.exit(-1);
                        return;
                    }
                    tcpList.add(tcpServer);
                }
            }
        }
        catch (Exception exception)
        {
            logger.error("启动失败",exception);
            this.destroy();
        }
    }

    private String checkServerName(List<HttpConfigProperties> http,List<TcpConfigProperties> tcp)
    {
        List<String> strings = new ArrayList<>();

        if (!CollectionUtils.isEmpty(http)) {
            for (HttpConfigProperties httpConfigProperties : http) {
                if(!strings.contains(httpConfigProperties.getServerId()))
                {
                    strings.add(httpConfigProperties.getServerId());
                    AgentServerDto agentServerDto = new AgentServerDto(httpConfigProperties.getServerKey(),ProxyTypeEnum.HTTP.code);
                    AgentChannelManager.agentServer.put(httpConfigProperties.getServerId(),agentServerDto);
                }
                else
                {
                    return httpConfigProperties.getServerId()+"：重复配置";
                }
            }
        }
        if (!CollectionUtils.isEmpty(tcp)) {
            for (TcpConfigProperties tcpProperties : tcp) {
                if(!strings.contains(tcpProperties.getServerId()))
                {
                    strings.add(tcpProperties.getServerId());
                    AgentServerDto agentServerDto = new AgentServerDto(tcpProperties.getServerKey(),ProxyTypeEnum.TCP.code);
                    AgentChannelManager.agentServer.put(tcpProperties.getServerId(),agentServerDto);
                }
                else
                {
                    return tcpProperties.getServerId()+"：重复配置";
                }
            }
        }
        return null;
    }
}
